package com.xiaoyg.algorithm.lfu;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;

public class LFUCache {
    //存储key -> value值
     Map<Integer,Integer> keyToVal;
    //存储key -> freq值
    Map<Integer, Integer> keyToFreq;
    //存储freq -> keys的值
    Map<Integer, LinkedHashSet<Integer>> freqToKeys;

    int minFreq;

    int cap;

    public LFUCache(int cap){
        keyToVal = new HashMap<>();
        keyToFreq = new HashMap<>();
        freqToKeys = new HashMap<>();
        this.cap = cap;
        this.minFreq = 0;
    }

    public int get(int key){
        if (keyToVal.containsKey(key)){
            increaseFreq(key);
            return keyToVal.get(key);
        }
        return -1;
    }

    public void put(int key, int val){
        if (keyToVal.containsKey(key)){
            keyToVal.put(key,val);
            increaseFreq(key);
            return;
        }

        if (this.cap <= keyToVal.size()){
            removeMinFreqKey();
        }

        keyToVal.put(key, val);

        //维护key2Freq,freq2Keys
        keyToFreq.put(key, 1);
        freqToKeys.putIfAbsent(1, new LinkedHashSet<>());
        freqToKeys.get(1).add(key);
        this.minFreq = 1;
    }

    private void increaseFreq(int key) {
        Integer freq = keyToFreq.get(key);
        keyToFreq.put(key,freq + 1);
        //删除掉freq
        freqToKeys.get(freq).remove(key);

        freqToKeys.putIfAbsent(freq + 1, new LinkedHashSet<>());
        freqToKeys.get(freq + 1).add(key);

        if (freqToKeys.get(freq).isEmpty()){
            freqToKeys.remove(freq);
            if (freq == this.minFreq){
                //如果原来freq最小，为空了，全部删除了，目前这个加1的才是最新的
                minFreq++;
            }
        }


    }

    private void removeMinFreqKey() {
        LinkedHashSet<Integer> minFredKeys = freqToKeys.get(this.minFreq);
        Integer minFredKey = minFredKeys.iterator().next();

        minFredKeys.remove(minFredKey);
        if (minFredKeys.isEmpty()){
            freqToKeys.remove(this.minFreq);
        }
        keyToVal.remove(minFredKey);
        keyToFreq.remove(minFredKey);
    }

}
